#pragma once 

#include <iostream>
#include <string>
#include <queue>

#define CAPACITY 1024

//消息池当中使用queue来保存消息，queue容器并不是线程安全的，是因为追求效率
//保证线程安全的机制：
//            互斥锁 + 条件变量(同步)
class MsgPool 
{
    public:
        MsgPool(size_t capa = CAPACITY)
        {
            capacity_ = capa;

            //锁的初始化
            pthread_mutex_init(&lock_que_, NULL);
            pthread_cond_init(&cond_con_, NULL);
            pthread_cond_init(&cond_pro_, NULL);
        }

        ~MsgPool()
        {
            //销毁锁
            pthread_mutex_destroy(&lock_que_);
            pthread_cond_destroy(&cond_con_);
            pthread_cond_destroy(&cond_pro_);
        }
        
        //进消息池（生产者）
        void PushMsg(const std::string& msg)
        {
            pthread_mutex_lock(&lock_que_);
            while(que_.size() >= capacity_)
            {
                pthread_cond_wait(&cond_pro_, &lock_que_); //没有多余的空间生产，就等待
            }
            que_.push(msg);    
            pthread_mutex_unlock(&lock_que_);
            pthread_cond_signal(&cond_con_); //有消息就通知消费者消费
        }

        //出消息池（消费者）
        void PopMsg(std::string* msg)
        {
            pthread_mutex_lock(&lock_que_);
            while(que_.empty())
            {
                pthread_cond_wait(&cond_con_, &lock_que_); //没有消息可读了，就等待
            }
            *msg = que_.front();
            que_.pop();
            pthread_mutex_unlock(&lock_que_);
            pthread_cond_signal(&cond_pro_); //消息被pop出去就通知生产者生产
        }
    private:
        std::queue<std::string> que_; //使用string对象保存消息
        size_t capacity_;

        pthread_mutex_t lock_que_; //保护消息容器的锁
        pthread_cond_t cond_con_; //消费者的条件变量
        pthread_cond_t cond_pro_; //生产者的条件变量
};
